package lew.bing.gwalo.annotations;

import com.google.common.util.concurrent.RateLimiter;
import lew.bing.gwalo.rateLimiter.Limiter;
import lew.bing.gwalo.utils.CommonUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJava;
import org.springframework.stereotype.Component;

/**
 * Created by 刘国兵 on 2018/7/8.
 * 只有在包含有guava时才可使用
 */
@Aspect
@Component
@ConditionalOnClass(value = RateLimiter.class)
public class RateLimitHandler {

    private static final Logger logger = LoggerFactory.getLogger(RateLimitHandler.class);

    @Autowired
    private Limiter limiter;

    @Around("@annotation(lew.bing.gwalo.annotations.RateLimit)")
    public Object handler(ProceedingJoinPoint pjp) {
        try {
            MethodSignature pjpSignature = (MethodSignature) pjp.getSignature();
            RateLimit rateLimit = pjpSignature.getMethod().getAnnotation(RateLimit.class);
            String key = CommonUtils.getKey(pjpSignature,rateLimit.key(),pjp.getArgs());
            String group = rateLimit.group();
            limiter.changeRate(group + ":" + key);// 先纠正速率

            RateLimiter limiter = this.limiter.takeLimiter(group, key, rateLimit.defaultRate());
            if (rateLimit.block()) {
                logger.debug("获取信号");
                limiter.acquire();
                logger.debug("获取成功");
                return pjp.proceed();
            } else {
                boolean b = limiter.tryAcquire();
                logger.debug("获取信号");
                if (b) {
                    logger.debug("获取成功");
                    return pjp.proceed();
                }else {
                    logger.debug("获取失败");
                    throw new IllegalAccessException("目前无法访问该方法");
                }
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }
    }

}
